#include "save_xml.h"
#include <QHash>
#include "../shape/action.h"
#include "../flow/flow.h"
#include "../flow/noteflow.h"
#include "../flow/arrowflow.h"
#include "../flow/flowtext.h"
#include "../shape/decision.h"
#include "../shape/note.h"
#include "../shape/initialnode.h"
#include "../shape/finalnode.h"
#include "../flow/tempshape.h"
#include <typeinfo>
#include <QXmlStreamWriter>
#include <QFile>
#include <QDebug>

typedef int ID;
typedef void (*SAVE_SHAPE_FUNC) (QXmlStreamWriter &x, Shape *shape, QHash<Shape *, ID> &ids);

void save_TempShape (QXmlStreamWriter &x, Shape *sh, QHash<Shape*, ID> &ids)
{
	TempShape *s = dynamic_cast<TempShape *>(sh);
	x.writeStartElement("TempShape");
	x.writeAttribute("ID",	QString::number(ids[s]));
	x.writeAttribute("x",	QString::number(s->pos().x()));
	x.writeAttribute("y",	QString::number(s->pos().y()));
	x.writeEndElement();
}

void saveFlowKnots (Flow *flow, QXmlStreamWriter &x)
{
	QPolygonF poly = flow->createFlowPolygon();
	x.writeAttribute("KnotsCount", QString::number(poly.count()-2));
	for(int i=1; i<poly.count()-1; ++i)
	{
		x.writeAttribute("KnotX_" + QString::number(i-1), QString::number(poly[i].x()));
		x.writeAttribute("KnotY_" + QString::number(i-1), QString::number(poly[i].y()));
	}
}

void save_NoteFlow (QXmlStreamWriter &x, Shape *s, QHash<Shape*, ID> &ids)
{
	NoteFlow *flow = dynamic_cast<NoteFlow *>(s);
	x.writeStartElement("NoteFlow");
	x.writeAttribute("ID", QString::number(ids[flow]));
	x.writeAttribute("fromID", QString::number(ids[flow->startShape()]));
	x.writeAttribute("toID", QString::number(ids[flow->endShape()]));
	saveFlowKnots(flow, x);
	x.writeEndElement();
}

void save_ActionShape (QXmlStreamWriter &x, Shape *sh, QHash<Shape*, ID> &ids)
{
	ActionShape *s = dynamic_cast<ActionShape *>(sh);
	x.writeStartElement("ActionShape");
	x.writeAttribute("ID",		QString::number(ids[s]));
	x.writeAttribute("x",		QString::number(s->pos().x()));
	x.writeAttribute("y",		QString::number(s->pos().y()));
	x.writeAttribute("width",	QString::number(s->size().width()));
	x.writeAttribute("height",	QString::number(s->size().height()));
	x.writeAttribute("title",	s->title());
	x.writeAttribute("description", s->description());
	x.writeEndElement();
}

void save_NoteShape (QXmlStreamWriter &x, Shape *sh, QHash<Shape*, ID> &ids)
{
	NoteShape *s = dynamic_cast<NoteShape *>(sh);
	x.writeStartElement("NoteShape");
	x.writeAttribute("ID",		QString::number(ids[s]));
	x.writeAttribute("x",		QString::number(s->pos().x()));
	x.writeAttribute("y",		QString::number(s->pos().y()));
	x.writeAttribute("width",	QString::number(s->size().width()));
	x.writeAttribute("height",	QString::number(s->size().height()));
	x.writeAttribute("title",	s->title());
	x.writeAttribute("description", s->description());
	x.writeEndElement();
}

void save_DecisionShape (QXmlStreamWriter &x, Shape *sh, QHash<Shape*, ID> &ids)
{
	DecisionShape *s = dynamic_cast<DecisionShape *>(sh);
	x.writeStartElement("DecisionShape");
	x.writeAttribute("ID",		QString::number(ids[s]));
	x.writeAttribute("x",		QString::number(s->pos().x()));
	x.writeAttribute("y",		QString::number(s->pos().y()));
	x.writeAttribute("width",	QString::number(s->size().width()));
	x.writeAttribute("height",	QString::number(s->size().height()));
	x.writeAttribute("corners", s->connectToCorners()?"true":"false");
	x.writeEndElement();
}

void save_ArrowFlow (QXmlStreamWriter &x, Shape *s, QHash<Shape*, ID> &ids)
{
	ArrowFlow *flow = dynamic_cast<ArrowFlow *>(s);
	x.writeStartElement("ArrowFlow");
	x.writeAttribute("ID",		QString::number(ids[flow]));
	x.writeAttribute("fromID",	QString::number(ids[flow->startShape()]));
	x.writeAttribute("toID",	QString::number(ids[flow->endShape()]));
	x.writeAttribute("offsetX", QString::number(flow->textShape()->offsetX()));
	x.writeAttribute("offsetY", QString::number(flow->textShape()->offsetY()));
	x.writeAttribute("text",	flow->text());
	saveFlowKnots(flow, x);
	x.writeEndElement();
}

void save_InitialNodeShape (QXmlStreamWriter &x, Shape *sh, QHash<Shape*, ID> &ids)
{
	InitialNodeShape *s = dynamic_cast<InitialNodeShape *>(sh);
	x.writeStartElement("InitialNodeShape");
	x.writeAttribute("ID",	QString::number(ids[s]));
	x.writeAttribute("x",	QString::number(s->pos().x()));
	x.writeAttribute("y",	QString::number(s->pos().y()));
	x.writeEndElement();
}

void save_FinalNodeShape (QXmlStreamWriter &x, Shape *sh, QHash<Shape*, ID> &ids)
{
	FinalNodeShape *s = dynamic_cast<FinalNodeShape *>(sh);
	x.writeStartElement("FinalNodeShape");
	x.writeAttribute("ID",	QString::number(ids[s]));
	x.writeAttribute("x",	QString::number(s->pos().x()));
	x.writeAttribute("y",	QString::number(s->pos().y()));
	x.writeEndElement();
}

void file_save_xml (const QString &filename, QGraphicsView *view, bool isdraft)
{
	QFile file(filename);
	if (!file.open(QIODevice::WriteOnly | QIODevice::Truncate))
		throw FileErrorException(filename);
	QTextStream stream(&file);
	stream << create_scene_xml(view->scene(), isdraft, view);
	file.close();
}

QString create_scene_xml (QGraphicsScene *view, bool isdraft, QGraphicsView *v)
{
	QHash<Shape*, ID> shapeids;
	QHash<QString, SAVE_SHAPE_FUNC> savefunc;

	QString str;
	QXmlStreamWriter writer(&str);
	writer.setAutoFormatting(true);
	writer.writeStartDocument();
	writer.writeStartElement("activityedit_xml");
	writer.writeAttribute("draft", (isdraft? "1" : "0"));

	if (v)
	{
		QSize sz = v->viewport()->size();
		QPointF pt = v->mapToScene(sz.width()/2, sz.height()/2);
		writer.writeAttribute("viewx", QString::number(pt.x()));
		writer.writeAttribute("viewy", QString::number(pt.y()));
	}

	/* Создаем таблицу ID */
	CustomGraphicsScene *scene = dynamic_cast<CustomGraphicsScene *>(view);
	QList<Shape *> items = scene->shapes();
	int curid = 0;
	foreach(Shape *item, items)
		shapeids[item] = curid++;

	/*
	 * быдлокод быдлополиморфизма на быдлосях
	 * чтобы никто не догадался
	 * ...
	 * В Shape я это пихать не буду, не место этому там
	 */
	savefunc[typeid(ActionShape).name()] = save_ActionShape;
	savefunc[typeid(NoteShape).name()] = save_NoteShape;
	savefunc[typeid(DecisionShape).name()] = save_DecisionShape;
	savefunc[typeid(InitialNodeShape).name()] = save_InitialNodeShape;
	savefunc[typeid(FinalNodeShape).name()] = save_FinalNodeShape;
	savefunc[typeid(ArrowFlow).name()] = save_ArrowFlow;
	savefunc[typeid(NoteFlow).name()] = save_NoteFlow;
	savefunc[typeid(TempShape).name()] = save_TempShape;


	foreach(Shape *item, items)
		if (savefunc[typeid(*item).name()])
			savefunc[typeid(*item).name()](writer, item, shapeids);
		else
			qDebug() << "unhandled shape: " << typeid(*item).name();

	writer.writeEndElement();
	writer.writeEndDocument();

	return str;
}
